package com.george.socket;

import com.george.entity.vo.ExceptionVo;
import com.george.enums.ConnectEnum;
import com.george.enums.ExceptionEnum;
import com.george.enums.LinkTypeEnum;
import com.george.enums.OptionEnum;
import com.george.server.TcpServerHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@Component
@ServerEndpoint("/option/{linkType}")
public class OptionSocket {

    /**
     * 连接集合
     */
    public static CopyOnWriteArrayList<OptionSocket> CONNECT = new CopyOnWriteArrayList<>();

    private Session session;

    /**
     * 连接类型
     */
    private LinkTypeEnum linkType;

    @OnOpen
    public void onOpen(@PathParam("linkType")String type, Session session) throws IOException {
        this.session = session;

        //获取连接类型枚举
        LinkTypeEnum linkType = LinkTypeEnum.getLinkTypeEnumByType(type);
        if (Objects.isNull(linkType)){
            throw new ExceptionVo(ExceptionEnum.BUSINESS_EXCEPTION,"连接类型不符合规范");
        }
        this.linkType = linkType;

        CONNECT.remove(this);
        CONNECT.add(this);
        log.debug("连接[{}]加入。当前连接数为：{}",this.session.getId(),CONNECT.size());
    }

    @OnClose
    public void onClose() {
        CONNECT.remove(this);
        log.debug("连接[{}]退出。当前连接数为：{}",this.session.getId(),CONNECT.size());
    }

    @Async
    @OnMessage
    public void onMessage(String option) throws Exception {
        log.debug("收到来自连接[{}]发送的消息：{}",this.session.getId(),option);
        this.sendMessage("Server has received msg: ["+ option +"]");  //回复连接

        //如果传输的数据不是系统定义的操作，则不需要进行处理
        OptionEnum optionEnum = OptionEnum.getOptionEnumByOption(option);
        if (Objects.isNull(optionEnum)){
            return;
        }
        //将操作转换成嵌入式设备能识别的操作（暂时不作相关处理，剔除杂余指令即可）
        String order = optionHandle(optionEnum);
        if (!Objects.isNull(order)){
            //向嵌入式设备发送数据
            try {
                TcpServerHandler.sendMessage(ConnectEnum.values()[0], order);
            }catch (ExceptionVo exceptionVo){
                log.warn(exceptionVo.getMessage());
            }
            log.debug("连接[{}]向设备发送消息：{}",this.session.getId(),order);
        }
    }

    @OnError
    public void onError(Throwable error) {
        CONNECT.remove(this);
        log.warn(error.getMessage());
    }

    /**
     * （目前是不做处理直接转发给嵌入式设备）
     * 将移动设备发来的指令转换成嵌入式设备所规定的指令
     * @param option 移动设备发送的指令
     * @return 嵌入式设备所规定的指令
     */
    private String optionHandle(OptionEnum option){
        //如果发送的指令与移动操作无关，则不需要向设备发送消息
        if (Objects.equals(OptionEnum.MONITOR_MOD,option)
                || Objects.equals(OptionEnum.PROGRAM_MOD,option)
                || Objects.equals(OptionEnum.STOP,option)
                || Objects.equals(OptionEnum.START,option)){
            return null;
        }
        return option.getOrder();
    }

    /**
     * 发送消息
     * @param message 消息
     * @throws IOException 发送消息的IO异常
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 向指定设备发送消息
     * @param linkType 设备类型
     * @param message 消息
     */
    public void sendMessage(LinkTypeEnum linkType, String message) throws IOException {
        for (OptionSocket socket : CONNECT) {
            if (Objects.equals(socket.linkType,linkType)){
                socket.sendMessage(message);
            }
        }
    }

}
